﻿using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace Devonline.Identity;

/// <summary>
/// 重载的身份上下文, 提供字符串类型主键的默认实现
/// </summary>
public class IdentityDbContext(DbContextOptions<IdentityDbContext> options) : IdentityDbContext<User, Role, UserClaim, UserRole, UserLogin, RoleClaim, UserToken, RealNameInfo, OAuthUser, Group, UserGroup, Level, Region, Resource, AccessRule, AccessApply, AccessRecord, Parameter, Attachment, string>(options);

/// <summary>
/// 重载的身份上下文, 提供字符串类型主键的默认实现
/// </summary>
/// <typeparam name="TKey"></typeparam>
public class IdentityDbContext<TKey>(DbContextOptions<IdentityDbContext<TKey>> options) : IdentityDbContext<User<TKey>, Role<TKey>, UserClaim<TKey>, UserRole<TKey>, UserLogin<TKey>, RoleClaim<TKey>, UserToken<TKey>, RealNameInfo<TKey>, OAuthUser<TKey>, Group<TKey>, UserGroup<TKey>, Level<TKey>, Region<TKey>, Resource<TKey>, AccessRule<TKey>, AccessApply<TKey>, AccessRecord<TKey>, Parameter<TKey>, Attachment<TKey>, TKey>(options) where TKey : IEquatable<TKey>, IConvertible;

/// <summary>
/// 重载的身份上下文
/// </summary>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TRole"></typeparam>
/// <typeparam name="TUserClaim"></typeparam>
/// <typeparam name="TUserRole"></typeparam>
/// <typeparam name="TUserLogin"></typeparam>
/// <typeparam name="TRoleClaim"></typeparam>
/// <typeparam name="TUserToken"></typeparam>
/// <typeparam name="TRealNameInfo"></typeparam>
/// <typeparam name="TOAuthUser"></typeparam>
/// <typeparam name="TGroup"></typeparam>
/// <typeparam name="TUserGroup"></typeparam>
/// <typeparam name="TLevel"></typeparam>
/// <typeparam name="TRegion"></typeparam>
/// <typeparam name="TResource"></typeparam>
/// <typeparam name="TAccessRule"></typeparam>
/// <typeparam name="TAccessApply"></typeparam>
/// <typeparam name="TAccessRecord"></typeparam>
/// <typeparam name="TParameter"></typeparam>
/// <typeparam name="TAttachment"></typeparam>
/// <typeparam name="TKey"></typeparam>
public class IdentityDbContext<TUser, TRole, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken, TRealNameInfo, TOAuthUser, TGroup, TUserGroup, TLevel, TRegion, TResource, TAccessRule, TAccessApply, TAccessRecord, TParameter, TAttachment, TKey>(DbContextOptions options) :
    IdentityDbContext<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken>(options)
    where TUser : User<TKey>
    where TRole : Role<TKey>
    where TUserClaim : UserClaim<TKey>
    where TUserRole : UserRole<TKey>
    where TUserLogin : UserLogin<TKey>
    where TRoleClaim : RoleClaim<TKey>
    where TUserToken : UserToken<TKey>
    where TRealNameInfo : RealNameInfo<TKey>
    where TOAuthUser : OAuthUser<TKey>
    where TGroup : Group<TKey>
    where TUserGroup : UserGroup<TKey>
    where TLevel : Level<TKey>
    where TRegion : Region<TKey>
    where TResource : Resource<TKey>
    where TAccessRule : AccessRule<TKey>
    where TAccessApply : AccessApply<TKey>
    where TAccessRecord : AccessRecord<TKey>
    where TParameter : Parameter<TKey>
    where TAttachment : Attachment<TKey>
    where TKey : IEquatable<TKey>, IConvertible
{
    #region identity core entities
    /// <summary>
    /// RealNameAuthUser
    /// </summary>
    public virtual DbSet<TRealNameInfo> RealNameAuthUsers => Set<TRealNameInfo>();
    /// <summary>
    /// OAuthUser
    /// </summary>
    public virtual DbSet<TOAuthUser> OAuthUsers => Set<TOAuthUser>();
    /// <summary>
    /// AuthorizeType
    /// </summary>
    public virtual DbSet<TLevel> Levels => Set<TLevel>();
    /// <summary>
    /// Region
    /// </summary>
    public virtual DbSet<TRegion> Regions => Set<TRegion>();
    /// <summary>
    /// Group
    /// </summary>
    public virtual DbSet<TGroup> Groups => Set<TGroup>();
    /// <summary>
    /// UserGroup
    /// </summary>
    public virtual DbSet<TUserGroup> UserGroups => Set<TUserGroup>();
    /// <summary>
    /// Resource
    /// </summary>
    public virtual DbSet<TResource> Resources => Set<TResource>();
    /// <summary>
    /// AccessRule
    /// </summary>
    public virtual DbSet<TAccessRule> AccessRules => Set<TAccessRule>();
    /// <summary>
    /// AccessApply
    /// </summary>
    public virtual DbSet<TAccessApply> AccessApplies => Set<TAccessApply>();
    /// <summary>
    /// AccessRecord
    /// </summary>
    public virtual DbSet<TAccessRecord> AccessRecords => Set<TAccessRecord>();
    /// <summary>
    /// 基础数据
    /// </summary>
    public virtual DbSet<TParameter> Parameters => Set<TParameter>();
    /// <summary>
    /// 附件
    /// </summary>
    public virtual DbSet<TAttachment> Attachments => Set<TAttachment>();
    #endregion

    protected override void OnModelCreating(ModelBuilder builder)
    {
        //base.OnModelCreating(builder);

        builder.Entity<TUser>(b =>
        {
            b.HasKey(x => x.Id);
            b.ToTable(typeof(TUser).GetTableName());
            b.Property(x => x.State).HasDefaultValue(DataState.Available);

            b.HasIndex(u => u.UserName).HasDatabaseName("ix_user_user_name").IsUnique();
            b.HasIndex(u => u.NormalizedUserName).HasDatabaseName("ix_user_normalized_user_name").IsUnique();
            b.HasIndex(u => u.PhoneNumber).HasDatabaseName("IX_user_phone_number");
            b.HasIndex(u => u.NormalizedEmail).HasDatabaseName("IX_user_email");
        });

        builder.Entity<TRole>(b =>
        {
            b.HasKey(x => x.Id);
            b.ToTable(typeof(TRole).GetTableName());
            b.Property(x => x.State).HasDefaultValue(DataState.Available);
        });

        builder.Entity<TUserRole>(b =>
        {
            b.HasKey(x => new { x.UserId, x.RoleId });
            b.ToTable(typeof(TUserRole).GetTableName());
        });

        builder.Entity<TUserLogin>(b =>
        {
            b.HasKey(x => new { x.LoginProvider, x.ProviderKey });
            b.ToTable(typeof(TUserLogin).GetTableName());
        });

        builder.Entity<TUserToken>(b =>
        {
            b.HasKey(x => new { x.UserId, x.LoginProvider, x.Name });
            b.ToTable(typeof(TUserToken).GetTableName());
        });

        builder.Entity<TUserClaim>().ToTable(typeof(TUserClaim).GetTableName());
        builder.Entity<TRoleClaim>().ToTable(typeof(TRoleClaim).GetTableName());
        builder.Entity<TOAuthUser>(b => b.Property(x => x.State).HasDefaultValue(DataState.Available));
        builder.Entity<TLevel>(b => b.Property(x => x.State).HasDefaultValue(DataState.Available));
        builder.Entity<TRegion>(b => b.Property(x => x.State).HasDefaultValue(DataState.Available));

        builder.Entity<TRealNameInfo>(b =>
        {
            b.ToTable(typeof(TRealNameInfo).GetTableName());
            b.Property(x => x.State).HasDefaultValue(DataState.Available);

            b.HasIndex(x => x.IdCode).HasDatabaseName("IX_real_name_info_id_code").IsUnique();
            b.HasIndex(u => u.PhoneNumber).HasDatabaseName("IX_real_name_info_phone_number");
        });

        builder.Entity<TGroup>(b =>
        {
            b.Property(x => x.State).HasDefaultValue(DataState.Available);
        });

        builder.Entity<TUserGroup>(b => b.HasKey(x => new { x.UserId, x.GroupId }));
        builder.Entity<TResource>(b => b.Property(x => x.State).HasDefaultValue(DataState.Available));
        builder.Entity<TAccessApply>(b => b.Property(x => x.State).HasDefaultValue(DataState.Available));
        builder.Entity<TAccessRecord>(b => b.Property(x => x.State).HasDefaultValue(DataState.Available));
        builder.Entity<TAccessRule>(b => b.Property(x => x.State).HasDefaultValue(DataState.Available));
        builder.Entity<TAttachment>(b => b.Property(x => x.State).HasDefaultValue(DataState.Available));
        builder.Entity<TParameter>(b => b.Property(x => x.State).HasDefaultValue(DataState.Available));
    }
}